package edu.hawaii.myisern.model;

import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.xml.bind.JAXBException;
import edu.hawaii.myisern.collaborations.jaxb.CollaboratingOrganizations;
import edu.hawaii.myisern.collaborations.jaxb.Collaboration;
import edu.hawaii.myisern.collaborations.jaxb.CollaborationTypes;
import edu.hawaii.myisern.collaborations.jaxb.Collaborations;
import edu.hawaii.myisern.collaborations.jaxb.OutcomeTypes;
import edu.hawaii.myisern.collaborations.jaxb.Years;
import edu.hawaii.myisern.organizations.jaxb.AffiliatedResearchers;
import edu.hawaii.myisern.organizations.jaxb.Organization;
import edu.hawaii.myisern.organizations.jaxb.Organizations;
import edu.hawaii.myisern.organizations.jaxb.ResearchKeywords;
import edu.hawaii.myisern.researchers.jaxb.Researcher;
import edu.hawaii.myisern.researchers.jaxb.Researchers;
import edu.hawaii.myisern.xml.MyIsernXmlLoader;
import edu.hawaii.myisern.xml.MyIsernXmlSaver;

/**
 * MyIsern model.
 * 
 * REMINDER --- Examples to look at: Request Parameters (http://lh:8080/examples)
 * Calendar Example in jst examples (cal1.jsp and cal2.jsp for printing and adding)
 * @author Sonwright M. Gomez
 *
 */
public class MyIsernModel {

  /** Private MyIsern Xml Loader. */
  private MyIsernXmlLoader mixl;
  private MyIsernXmlSaver mixs;
  private Researchers researchers = new Researchers();
  private Organizations organizations = new Organizations();
  private Collaborations collaborations = new Collaborations();
  private List<Researcher> listR = new ArrayList<Researcher>();
  private List<Organization> listO = new ArrayList<Organization>();
  private List<Collaboration> listC = new ArrayList<Collaboration>();
  private String comma = ", ";
  
  /** The singleton StackModel instance. */
  private static MyIsernModel theInstance = new MyIsernModel();
  
  /** constructor for MyIsernModel */
  private MyIsernModel() {
    try {
      this.mixl = new MyIsernXmlLoader();
      this.mixs = new MyIsernXmlSaver();
      this.researchers = mixl.getResearchers();
      this.organizations = mixl.getOrganizations();
      this.collaborations = mixl.getCollaborations();
      
      this.listR = this.researchers.getResearcher();
      this.listO = this.organizations.getOrganization();
      this.listC = this.collaborations.getCollaboration();
    }
    catch (Exception error) {
      // TODO Auto-generated catch block
      error.printStackTrace();
    }
  }
  
  /**
   * Get's a researcher according to string name.
   * @param name of researcher
   * @return Researcher if found.
   */
  public synchronized Researcher getResearcher(String name) {
    Researcher researcher = new Researcher();
    for (Researcher curr : this.listR) {
      if (name.equals(curr.getName())) {
        researcher = curr;
        break;
      }
    }
    return researcher;
  }
  
  /**
   * Get's Organization according to String.
   * @param name of organization
   * @return Organization if found.
   */
  public synchronized Organization getOrganization(String name) {
    Organization organization = new Organization();
    for (Organization curr : this.listO) {
      if (name.equals(curr.getName())) {
        organization = curr;
        break;
      }
    }
    return organization;
  }
  
  /**
   * Get's collaboration according to string name.
   * @param name of collaboration
   * @return Collaboration if found.
   */
  public synchronized Collaboration getCollaboration(String name) {
    Collaboration collaboration = new Collaboration();
    for (Collaboration curr : this.listC) {
      if (name.equals(curr.getName())) {
        collaboration = curr;
        break;
      }
    }
    return collaboration;
  }
  
  /**
   * Get's Id's for Researchers
   * @return List<String> of Id's
   */
  public synchronized List<String> getResearcherIds() {
    return mixl.getListResearchers();
  }
  
  /**
   * Get's Id's for Collaborations
   * @return List<String> of Id's
   */
  public synchronized List<String> getCollaborationIds() {
    return mixl.getListCollaborations();
  }
  
  /**
   * Get's Id's for Organizations
   * @return List<String> of Id's
   */
  public synchronized List<String> getOrganizationIds() {
    return mixl.getListOrganizations();
  }
  
  /**
   * Checks if researcher exists.
   * @param possibleResearcher name of possible researcher.
   * @return boolean if researcher exists.
   */
  public synchronized boolean containsResearcher(String possibleResearcher) {
    return mixl.containsResearcher(possibleResearcher);
  }
  
  /**
   * Checks if organization exists.
   * @param possibleOrganization name of possible organization
   * @return boolean if organization exists.
   */
  public synchronized boolean containsOrganization(String possibleOrganization) {
    return mixl.containsOrganization(possibleOrganization);

  }
  
  /**
   * Checks if collaboration exists.
   * @param possibleCollaboration name of possible collaboration
   * @return boolean if collaboration exists.
   */
  public synchronized boolean containsCollaboration (String possibleCollaboration) {
    return mixl.containsCollaboration(possibleCollaboration);

  }
  
  /**
   * Get the single instance of MyIsernModel object.
   *
   * @return A MyIsernModel.
   */
  public static synchronized MyIsernModel getInstance() {
    return MyIsernModel.theInstance;
  }
  
  /**
   * Deletes collaboration if it exists in list.
   * @param oldCollaboration containing the Collaboration to be deleted.
   */
  public synchronized void deleteCollaboration(String oldCollaboration) {
    if (this.mixl.containsCollaboration(oldCollaboration.replace(' ', '_'))) {
      List<Collaboration> temp = new ArrayList<Collaboration>();
     
      //2 step process to delete a collaboration to avoid error
      for (Collaboration curr : this.listC) {
        if (oldCollaboration.equalsIgnoreCase(curr.getName())) {
          temp.add(curr);
        }
      }
      this.listC.removeAll(temp);
    }
  }
  
  /**
   * Deletes organization if it exists in list.
   * @param oldOrganization containing the organization to be deleted.
   */
  public synchronized void deleteOrganization(String oldOrganization) {
    if (this.mixl.containsOrganization(oldOrganization.replace(' ', '_'))) {
      List<Organization> temp = new ArrayList<Organization>();
      
      for (Organization curr : this.listO) {
        if (oldOrganization.equalsIgnoreCase(curr.getName())) {
          temp.add(curr);
        }
      }
      this.listO.removeAll(temp);
    }
  }
  
  
  /**
   * Deletes a researcher if it exists in the list.
   * @param oldResearcher containing the researcher to be deleted.
   */
  public synchronized void deleteResearcher(String oldResearcher) {
    if (this.mixl.containsResearcher(oldResearcher.replace(' ', '_'))) {
      List<Researcher> temp = new ArrayList<Researcher>();
      
      for (Researcher curr : this.listR) {
        if (oldResearcher.equalsIgnoreCase(curr.getName())) {
          temp.add(curr);
        }
      }
      this.listR.removeAll(temp);
    }
  }
  
  /**
   * Adds a new collaboration to the loader.
   * @param newCollaboration containing the new Collaboration to be added.
   */
  public synchronized void addCollaboration(Collaboration newCollaboration) {
    this.listC.add(newCollaboration);
  }
  
  /**
   * Adds a new organization to the loader.
   * @param newOrganization containing the new organization to be added.
   */
  public synchronized void addOrganization(Organization newOrganization) {
    this.listO.add(newOrganization);
  }
  
  
  /**
   * Adds a new researcher to the loader.
   * @param newResearcher containing the new researcher to be added.
   */
  public synchronized void addResearcher(Researcher newResearcher) {
    this.listR.add(newResearcher);
  }
  
  /**
   * Saves collaboration that has been added from Action Bean.
   * 
   * @throws JAXBException if JAXB Exception is encountered
   * @throws IOException if IOException is encountered
   */
  public synchronized void saveCollaboration() throws JAXBException, IOException {
    Collaborations newC = new Collaborations();
    for (Collaboration curr : this.listC) {
      newC.getCollaboration().add(curr);
    }
    mixs.saveCollaboratotionsXml(newC);
    
  }
  
  /**
   * Saves Organizations that has been added from Action Bean.
   * 
   * @throws JAXBException if JAXB Exception is encountered
   * @throws IOException if IOException is encountered
   */
  public synchronized void saveOrganizations() throws JAXBException, IOException {
    Organizations newO = new Organizations();
    for (Organization curr : this.listO) {
      newO.getOrganization().add(curr);
    }
    mixs.saveOrganizationsXml(newO);
  }
  
  /**
   * Saves Researcher that has been added from Action Bean.
   * 
   * @throws JAXBException if JAXB Exception is encountered
   * @throws IOException if IOException is encountered
   */
  public synchronized void saveResearcher() throws JAXBException, IOException {
    Researchers newR = new Researchers();
    for (Researcher curr : this.listR) {
      newR.getResearcher().add(curr);
    }
    try {
    mixs.saveResearchersXml(newR);
    }
    catch (Exception e) {
      e.getMessage();
    }
  }
  
  /**
   * Converts Affiliated Researchers to a string with commas.
   * @param ar containing Affiliated Researchers
   * @return String contains string of Affiliated Researchers.
   */
  public synchronized String arToString(AffiliatedResearchers ar) {
    List <AffiliatedResearchers> arList = new ArrayList<AffiliatedResearchers>();
    arList.add(ar);
    String string = "";
    for (AffiliatedResearchers curr : arList) {
      String temp = curr.getAffiliatedResearcher().toString()
      .replace('[', ' ').replace(']', ' ').trim();
      string += temp + comma;
    }
    return string;
  }
  
  /**
   * Converts Research Keywords to a string with commas.
   * @param rk containing research keywords to be converted.
   * @return String contains string of research keywords.
   */
  public synchronized String rkToString(ResearchKeywords rk) {
    List<ResearchKeywords> rkList = new ArrayList<ResearchKeywords>();
    rkList.add(rk);
    String string = "";
    for (ResearchKeywords curr : rkList) {
      String temp = curr.getResearchKeyword().toString()
      .replace('[', ' ').replace(']', ' ').trim();
      string += temp + comma;
    }
    return string;
  }
  
  /**
   * Converts Collaborating organizations list to a string with commas.
   * @param co containing organizations that are in collaboration.
   * @return String containing converted string from a list.
   */
  public synchronized String coToString(CollaboratingOrganizations co) {
    List<CollaboratingOrganizations> coList = new ArrayList<CollaboratingOrganizations>();
    coList.add(co);
    String string = "";
    for (CollaboratingOrganizations curr : coList) {
      String temp = curr.getCollaboratingOrganization().toString()
      .replace('[', ' ').replace(']', ' ').trim();
      string += temp + comma;
    }
    return string;
  }
  
  /**
   * Converts Collaboration Types to a string.
   * @param ct containing collaboration types to be converted.
   * @return String containing converted string from collaboration types.
   */
  public synchronized String ctToString(CollaborationTypes ct) {
    List<CollaborationTypes> ctList = new ArrayList<CollaborationTypes>();
    ctList.add(ct);
    String string = "";
    for (CollaborationTypes curr : ctList) {
      String temp = curr.getCollaborationType().toString()
      .replace('[', ' ').replace(']', ' ').trim();
      string += temp + comma;
    }
    return string;
  }
  
  /**
   * Converts Years to a string.
   * @param years to be converted to string.
   * @return String representation of years with commas.
   */
  public synchronized String yearsToString(Years years) {
    List<Years> yList = new ArrayList<Years>();
    yList.add(years);
    String string = "";
    for (Years curr : yList) {
      String temp = curr.getYear().toString().replace('[', ' ').replace(']', ' ').trim();
      string += temp + comma;
    }
    
    return string;
  }
  
  /**
   * Converts Outcome types to string.
   * @param ot containing Outcome types to be converted.
   * @return String representation of Outcome types with commas.
   */
  public synchronized String otToString(OutcomeTypes ot) {
    List<OutcomeTypes> otList = new ArrayList<OutcomeTypes>();
    otList.add(ot);
    String string = "";
    for (OutcomeTypes curr : otList) {
      String temp = curr.getOutcomeType().toString().replace('[', ' ').replace(']', ' ').trim();
      string += temp + comma;
    }
    return string;
  }
  
  /**
   * Checks if year entered is valid.
   * 
   * @param currentYear String that contains year to be converted and examined.
   * @return boolean whether year entered is valid.
   */
  public boolean yearIsValid(String currentYear) {
    boolean yearIsValid = false;
    try {
      BigInteger bigNum = new BigInteger(currentYear);
      if (bigNum.intValue() >= 1990 && bigNum.intValue() <= 2010) {
        yearIsValid = true;
      }
    }
    catch (Exception e) {
      System.out.println("Year format wrong.");
      yearIsValid = false;
    }
    return yearIsValid;
  }
  
  /**
   * Gets the iterator attribute of the StackModel object.
   *
   * @return The iterator value.
   */
  public synchronized Iterator<Organization> oIterator() {
    return this.listO.iterator();
  }
  
  /**
   * Gets the iterator attribute of the StackModel object.
   *
   * @return The iterator value.
   */
  public synchronized Iterator<Researcher> rIterator() {
    return this.listR.iterator();
  }
  
  /**
   * Gets the iterator attribute of the StackModel object.
   *
   * @return The iterator value.
   */
  public synchronized Iterator<Collaboration> cIterator() {
    return this.listC.iterator();
  }
}
